/*
 * Copyright (C) 2023 InConnect. All rights reserved.
 */
package main

import (
	"dqauthsvc/src/app"
	auth_svc "dqauthsvc/src/svc/auth"
	"dqbasepkg/grpcx"
	"dqbasepkg/log"
	"flag"
	"fmt"
	"github.com/rs/cors"
	rpcxlog "github.com/smallnest/rpcx/log"
	"github.com/smallnest/rpcx/server"
	"github.com/soheilhy/cmux"
	"net"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"syscall"
)

func serveGRPC(m cmux.CMux) {
	gs := grpcx.NewGrpcServerPlugin("", nil)
	gs.RegisterService(auth_svc.Register)
	gs.MuxMatch(m)
	if err := gs.Start(); err != nil && !strings.Contains(err.Error(), "server closed") {
		log.Fatal("gs.Start error", log.ErrorT(err))
	}
}

func serveHTTP(m cmux.CMux, h http.Handler) {
	l := m.Match(cmux.HTTP1Fast())
	s := &http.Server{
		Handler: h,
	}
	if err := s.Serve(l); err != nil && !strings.Contains(err.Error(), "server closed") {
		log.Fatal("http.Serve error", log.ErrorT(err))
	}
}

func main() {
	configPath := flag.String("config", "./config/config.toml", "config path")
	flag.Parse()

	if err := app.LoadConfig(configPath); err != nil {
		fmt.Println("LoadConfig error:", err)
		return
	}

	logLevel := log.InfoLevel
	switch app.Config.Log.Level {
	case "DEBUG":
		logLevel = log.DebugLevel
	case "INFO":
		logLevel = log.InfoLevel
	case "WARN":
		logLevel = log.WarnLevel
	case "ERROR":
		logLevel = log.ErrorLevel
	case "DPANIC":
		logLevel = log.DPanicLevel
	case "PANIC":
		logLevel = log.PanicLevel
	case "FATAL":
		logLevel = log.FatalLevel
	default:
		fmt.Println("invalid log level:", app.Config.Log.Level)
	}

	var tops = []log.TeeOption{
		{
			Filename: "stderr",
			Lef: func(lvl log.Level) bool {
				return lvl >= logLevel
			},
		},
		{
			Filename: app.Config.Log.FileName,
			Ropt: log.RotateOptions{
				MaxSize:    app.Config.Log.MaxSize,
				MaxAge:     app.Config.Log.MaxAge,
				MaxBackups: app.Config.Log.MaxBackups,
				LocalTime:  app.Config.Log.LocalTime,
				Compress:   app.Config.Log.Compress,
			},
			Lef: func(lvl log.Level) bool {
				return lvl >= logLevel
			},
		},
	}

	logger := log.NewTeeWithRotate(tops, log.WithCaller(true),
		log.AddCallerSkip(1), log.AddStacktrace(log.ErrorLevel))
	log.ResetDefault(logger)

	logger2 := log.NewWithSameCore(logger, log.WithCaller(true),
		log.AddCallerSkip(3), log.AddStacktrace(log.ErrorLevel))
	rpcxlog.SetLogger(log.NewRpcxLog(logger2))

	defer log.Sync()

	newServer := http.NewServeMux()
	newServer.HandleFunc("/dqauth", auth_svc.HandleAuth)

	c := cors.New(cors.Options(*server.AllowAllCORSOptions()))
	httpmux := c.Handler(newServer)

	l, err := net.Listen("tcp", app.Config.Common.Addr)
	if err != nil {
		log.Error("net.Listen error", log.ErrorT(err))
		return
	}

	// https://hypermode.com/blog/cmux
	tcpm := cmux.New(l)

	go serveGRPC(tcpm)
	go serveHTTP(tcpm, httpmux)

	// 设置中断信号处理
	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		<-c
		if err := l.Close(); err != nil {
			log.Error("server close error:", log.ErrorT(err))
		}
	}()

	log.Info("serve at:", log.String("addr", app.Config.Common.Addr))
	err = tcpm.Serve()
	if err != nil && !strings.Contains(err.Error(), "use of closed network connection") {
		log.Error("serve error:", log.ErrorT(err))
	}

	log.Info("serve end")
}
